/*
 * This file (AxLog.java) is protected by the GNU GPL licence (v2). 
 * Please read the license.txt attached for further informations. 
 * 
 */

package artx.utils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;

import artx.events.AxLogEvent;
import artx.listeners.AxLogListener;

/**
 * Provides interfaces to log text from the application. <br/> Listeners can be
 * added to catch all messages when they are logged, to add a visual output for
 * the user. <br/> A basic Listener has been implemented using
 * System.out.println.
 * 
 * @author Xavier Gouchet
 * @see artx.listeners.AxLogListener
 */

public class AxLog implements AxConstants {

	/** Verbosity level of the log */
	private static int VERBOSITY = 4;

	/** Standard log, used for users */
	private static ArrayList<String> STD_LOG = null;

	/** Debug log, used for developpers */
	private static ArrayList<String> DBG_LOG = null;

	/** Event listener for log events (new messages) */
	private static ArrayList<AxLogListener> LISTENERS = null;

	/**
	 * Unique way to log a message in the log.
	 * 
	 * @param msg
	 *            message to log
	 * @param lvl
	 *            verbosity level of the message
	 */
	private static void LogMessage(String msg, int lvl, String prefix) {
		if ((lvl <= VERBOSITY) && (lvl != LVL_DEBUG)) {
			// if log is null, we create it
			if (STD_LOG == null) {
				STD_LOG = new ArrayList<String>();
			}

			// we add the message
			STD_LOG.add(new String(msg));

			// create Log Event
			if (LISTENERS != null) {
				AxLogEvent e = new AxLogEvent(lvl, msg);
				int size = LISTENERS.size();
				for (int i = 0; i < size; i++) {
					LISTENERS.get(i).messageRegistered(e);
				}
			}
		}

		// if message is at debug level, we also add it to the debug log
		if (lvl == LVL_DEBUG) {
			// if debug log i null, we create it
			if (DBG_LOG == null) {
				DBG_LOG = new ArrayList<String>();
			}

			// we add the message
			DBG_LOG.add(msg);

			// create Log Event
			if (LISTENERS != null) {
				AxLogEvent e = new AxLogEvent(lvl, msg);
				int size = LISTENERS.size();
				for (int i = 0; i < size; i++) {
					LISTENERS.get(i).debugMessageRegistered(e);
				}
			}
		}
	}

	/**
	 * Add an error message to the log (if verbosity is high enough).
	 * 
	 * @param msg
	 *            the message to log
	 */
	public static void Error(String msg) {
		LogMessage(msg, LVL_ERROR, PREFIX_ERROR);
	}

	/**
	 * Add a warning message to the log (if verbosity is high enough).
	 * 
	 * @param msg
	 *            the message to log
	 */
	public static void Warning(String msg) {
		LogMessage(msg, LVL_WARNING, PREFIX_WARNING);
	}

	/**
	 * Add an info message to the log (if verbosity is high enough).
	 * 
	 * @param msg
	 *            the message to log
	 */
	public static void Info(String msg) {
		LogMessage(msg, LVL_INFO, PREFIX_INFO);
	}

	/**
	 * Add a debug message to the log (if verbosity is high enough).
	 * 
	 * @param msg
	 *            the message to log
	 */
	public static void Debug(String msg) {
		LogMessage(msg, LVL_DEBUG, PREFIX_DEBUG);
	}

	/**
	 * Sets the verbosity level of the log.
	 * 
	 * @param v
	 *            the verbosity level :
	 *            <ul>
	 *            <li>0 : No output;</li>
	 *            <li>1 : Errors only;</li>
	 *            <li>2 : Warnings and Errors</li>
	 *            <li>3 : Info, Warnings and Errors</li>
	 *            <li>4 : (Debug Level) All Messages</li>
	 *            </ul>
	 */
	public static void SetVerbosity(int v) {
		if ((v >= 0) && (v <= 4)) {
			VERBOSITY = (int) v;
			Info("Log Level set to " + v);
		}
	}

	/**
	 * Adds a listener on Log Events.
	 * 
	 * @param l
	 *            the listener to add
	 */
	public static void AddLogListener(AxLogListener l) {
		if (LISTENERS == null) {
			LISTENERS = new ArrayList<AxLogListener>();
			Debug("AxLog::SetLogListener =>> Listeners list created.");
		}

		LISTENERS.add(l);
	}

	/**
	 * Removes the current log listener.
	 * 
	 * @param listener
	 *            the listener to remove
	 */
	public static void RemoveLogListener(AxLogListener listener) {
		if (LISTENERS != null) {
			if (LISTENERS.contains(listener)) {
				LISTENERS.remove(listener);
			}
		}
	}

	/**
	 * Save the log in a 'standard.log' file in the root folder.
	 */
	public static void SaveLog() {
		// test if log exists
		if (STD_LOG == null) {
			Error("Can't save log for it is empty.");
		}

		// log is always saved in the local folder
		String path = "standard.log";

		// Save the log
		try {
			Debug("AxLog::SaveLog =>> creating output file");
			File f = new File(path);
			Writer output = new BufferedWriter(new FileWriter(f));
			Debug("AxLog::SaveLog =>> writing log content");
			int logCount = STD_LOG.size();
			for (int i = 0; i < logCount; i++) {
				output.write(STD_LOG.get(i).toString() + "\n");
			}
			Debug("AxLog::SaveLog =>> closing output file");
			output.close();
		} catch (IOException e) {
			Error("File Writting Error : " + e.getMessage());
		}
	}

	/**
	 * Save the debug log in a 'debug.log' file in the root folder.
	 */
	public static void SaveDebugLog() {
		// test if log exists
		if (DBG_LOG == null) {
			Error("Can't save debug log for it is empty.");
		}

		// log is always saved in the local folder
		String path = "debug.log";

		// Save the log
		try {
			Debug("AxLog::SaveDebugLog =>> creating output file");
			File f = new File(path);
			Writer output = new BufferedWriter(new FileWriter(f));
			Debug("AxLog::SaveDebugLog =>> writing log content");
			int logCount = DBG_LOG.size();
			for (int i = 0; i < logCount; i++) {
				output.write(DBG_LOG.get(i).toString() + "\n");
			}
			Debug("AxLog::SaveDebugLog =>> closing output file");
			output.write("AxLog::SaveDebugLog =>> closing output file\n");
			output.close();
		} catch (IOException e) {
			Error("File Writting Error : " + e.getMessage());
		}
	}

	/**
	 * Returns a list of string containing the complete log history.
	 * 
	 * @return the log history
	 */
	public static String[] GetLog() {
		if (STD_LOG != null) {
			String[] res = new String[STD_LOG.size()];
			for (int i = 0; i < STD_LOG.size(); i++) {
				res[i] = new String(STD_LOG.get(i));
			}
			return res;
		}
		return null;
	}

	/**
	 * Returns a list of string containing the complete debug log history.
	 * 
	 * @return the debug log history
	 */
	public static String[] GetDebugLog() {
		if (DBG_LOG != null) {
			String[] res = new String[DBG_LOG.size()];
			for (int i = 0; i < DBG_LOG.size(); i++) {
				res[i] = new String(DBG_LOG.get(i));
			}
			return res;
		}
		return null;
	}
}
